<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>无缝轮播图有问题</title>
</head>

<body>


  纯js手搓轮播图，平滑过渡动画，首尾无缝衔接
  https://juejin.cn/post/7092766701707591710 有问题
  <div class="swiper">
    <div class="swiper-img">
      <img src="https://sofile.cn/wp-content/uploads/img_test/5.jpg" alt="" />
      <img src="https://sofile.cn/wp-content/uploads/img_test/1.jpg" alt="" />
      <img src="https://sofile.cn/wp-content/uploads/img_test/2.jpg" alt="" />
      <img src="https://sofile.cn/wp-content/uploads/img_test/3.jpg" alt="" />
    </div>
    <ul class="swiper-point">
      <li class="active"></li>
      <li>1</li>
      <li>2</li>
      <li>3</li>
    </ul>
    <span class="left-btn">&lt;</span>
    <span class="right-btn">&gt;</span>
  </div>

  <style>
    .swiper {
      width: 1200px;
      height: 500px;
      margin: 50px auto;
      position: relative;
      overflow: hidden;
    }

    .swiper-img {
      position: absolute;
      top: 0;
      left: 0px;
      width: 100%;
      height: 100%;
      display: flex;
      transition: 0.5s ease;
    }

    .swiper-img img {
      width: 1200px;
      height: 100%;
    }

    .swiper-point {
      position: absolute;
      bottom: 5px;
      left: 50%;
      transform: translate(-50%, -50%);
      display: flex;
    }

    .swiper-point li {
      cursor: pointer;
      list-style: none;
      width: 40px;
      height: 4px;
      margin: 5px;
      border-radius: 2px;
      /* background-color: rgba(255,255,255,.8); */
      background-color: #9f9f9f;
      transition: 0.3s ease;
    }

    .swiper-point li:hover {
      background-color: #3498db;
    }

    .swiper-point li.active {
      background-color: #fff;
    }

    .swiper span {
      user-select: none;
      cursor: pointer;
      display: block;
      position: absolute;
      width: 50px;
      height: 50px;
      text-align: center;
      line-height: 50px;
      font-size: 20px;
      background-color: rgba(0, 0, 0, 0.6);
      color: #fff;
      border-radius: 50%;
    }

    .left-btn {
      top: 45%;
      left: 10px;
    }

    .right-btn {
      top: 45%;
      right: 10px;
    }
  </style>

  <script>
    // 获取图片列表
    const swiperImg = document.querySelector(".swiper-img");
    // 获取li列表
    const lis = document.querySelectorAll(".swiper-point li");
    // 图片宽度
    const imgWidth = 1200;
    // 获取按钮
    const leftBtn = document.querySelector(".left-btn");
    const rightBtn = document.querySelector(".right-btn");
    // 克隆第一张图片，添加到图片列表的最后
    let cloneImg = swiperImg.firstElementChild.cloneNode();
    swiperImg.appendChild(cloneImg);

    let index = 0; //图片的坐标

    let lock = true; //设置节流

    let timer = null; //设置定时器

    // 单击事件
    rightBtn.onclick = () => {
      // 判断锁的状态,如果是关闭就直接return
      if (!lock) return;
      // 移动位置
      index++;
      // 给下面去掉动画重新加上动画
      swiperImg.style.transition = ".5s ease";
      // 当坐标等于最后一张图片时
      if (index === swiperImg.children.length - 1) {
        // 迅速切换到第一张图片
        setTimeout(() => {
          swiperImg.style.left = 0;
          index = 0;
          changeLi(index);
          // 取消过渡动画,无缝衔接第一张图片
          swiperImg.style.transition = "none";
        }, 500);
      }
      swiperImg.style.left = `${-index * imgWidth}px`;
      if (index < swiperImg.children.length - 1) {
        changeLi(index);
      }
      // 关锁
      lock = false;
      // 500毫秒后开锁
      setTimeout(() => {
        lock = true;
      }, 500);
    };

    // 改变li的样式
    function changeLi(index) {
      lis.forEach((li) => {
        if (li.classList.contains("active")) {
          li.classList.remove("active");
        }
      });
      lis[index].classList.add("active");
    }

    // 左击事件
    leftBtn.onclick = () => {
      // 判断锁的状态,如果是关闭就直接return
      if (!lock) return;
      // 如果现在是第一张图片时
      if (index === 0) {
        // 切换到克隆的图片
        swiperImg.style.left = `${-(swiperImg.children.length - 1) * imgWidth}px`;

        // 取消动画,瞬间过去
        swiperImg.style.transition = "none";
        setTimeout(() => {
          // 真正的最后一张图
          index = swiperImg.children.length - 2;
          changeLi(index);
          // 加上动画
          swiperImg.style.transition = ".5s ease";
          swiperImg.style.left = `${-index * imgWidth}px`;
        });
      } else {
        index--;
        swiperImg.style.left = `${-index * imgWidth}px`;
        changeLi(index);
      }
      // 关锁;
      lock = false;
      // 500毫秒后开锁
      setTimeout(() => {
        lock = true;
      }, 500);
    };

    // li点击事件
    lis.forEach((li, idx) => {
      li.onclick = () => {
        index = idx;
        swiperImg.style.left = `${-index * imgWidth}px`;
        changeLi(index);
      };
    });

    // 轮播方法
    function auto() {
      // leftBtn.click();
      rightBtn.click();
    }
    // 定时轮播
    timer = setInterval(() => {
      auto();
    }, 3000);

    swiperImg.onmouseover = () => {
      clearInterval(timer);
    };

    swiperImg.onmouseout = () => {
      timer = setInterval(() => {
        auto();
      }, 3000);
    };
  </script>
</body>

</html>